{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 优化数据处理\n",
    "\n",
    "`Linux` `Ascend` `GPU` `CPU` `数据准备` `中级` `高级`\n",
    "\n",
    "[![](https://gitee.com/mindspore/docs/raw/master/resource/_static/logo_source.png)](https://gitee.com/mindspore/docs/blob/master/tutorials/training/source_zh_cn/advanced_use/optimize_data_processing.ipynb)&emsp;[![](https://gitee.com/mindspore/docs/raw/master/resource/_static/logo_notebook.png)](https://obs.dualstack.cn-north-4.myhuaweicloud.com/mindspore-website/notebook/master/mindspore_optimize_data_processing.ipynb)&emsp;[![](https://gitee.com/mindspore/docs/raw/master/resource/_static/logo_modelarts.png)](https://authoring-modelarts-cnnorth4.huaweicloud.com/console/lab?share-url-b64=aHR0cHM6Ly9vYnMuZHVhbHN0YWNrLmNuLW5vcnRoLTQubXlodWF3ZWljbG91ZC5jb20vbWluZHNwb3JlLXdlYnNpdGUvbm90ZWJvb2svbW9kZWxhcnRzL21pbmRzcG9yZV9vcHRpbWl6ZV90aGVfcGVyZm9ybWFuY2Vfb2ZfZGF0YV9wcmVwYXJhdGlvbi5pcHluYg==&imagename=MindSpore1.1.1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 概述\n",
    "\n",
    "数据是整个深度学习中最重要的一环，因为数据的好坏决定了最终结果的上限，模型的好坏只是去无限逼近这个上限，所以高质量的数据输入，会在整个深度神经网络中起到积极作用，数据在整个数据处理和数据增强的过程像经过pipeline管道的水一样，源源不断地流向训练系统，如图所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![pipeline](https://gitee.com/mindspore/docs/raw/master/tutorials/training/source_zh_cn/advanced_use/images/pipeline.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "MindSpore为用户提供了数据处理以及数据增强的功能，在数据的整个pipeline过程中，其中的每一步骤，如果都能够进行合理的运用，那么数据的性能会得到很大的优化和提升。本次体验将基于CIFAR-10数据集来为大家展示如何在数据加载、数据处理和数据增强的过程中进行性能的优化。\n",
    "\n",
    "此外，操作系统的存储、架构和计算资源也会一定程度上影响数据处理的性能。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 准备环节"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 导入模块"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`dataset`模块提供API用来加载和处理数据集。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import mindspore.dataset as ds"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`numpy`模块用于生成ndarray数组。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 下载所需数据集"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "运行以下命令来获取数据集：\n",
    "\n",
    "下载CIFAR-10二进制格式数据集，并将数据集文件解压到`./datasets/`目录下，数据加载的时候使用该数据集。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./datasets/cifar-10-batches-bin\n",
      "├── readme.html\n",
      "├── test\n",
      "│   └── test_batch.bin\n",
      "└── train\n",
      "    ├── batches.meta.txt\n",
      "    ├── data_batch_1.bin\n",
      "    ├── data_batch_2.bin\n",
      "    ├── data_batch_3.bin\n",
      "    ├── data_batch_4.bin\n",
      "    └── data_batch_5.bin\n",
      "\n",
      "2 directories, 8 files\n"
     ]
    }
   ],
   "source": [
    "!wget -N https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-binary.tar.gz\n",
    "!mkdir -p datasets\n",
    "!tar -xzf cifar-10-binary.tar.gz -C datasets\n",
    "!mkdir -p datasets/cifar-10-batches-bin/train datasets/cifar-10-batches-bin/test\n",
    "!mv -f datasets/cifar-10-batches-bin/test_batch.bin datasets/cifar-10-batches-bin/test\n",
    "!mv -f datasets/cifar-10-batches-bin/data_batch*.bin datasets/cifar-10-batches-bin/batches.meta.txt datasets/cifar-10-batches-bin/train\n",
    "!tree ./datasets/cifar-10-batches-bin"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下载CIFAR-10 Python文件格式数据集，并将数据集文件解压到`./datasets/cifar-10-batches-py`目录下，数据转换的时候使用该数据集。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "./datasets/cifar-10-batches-py\n",
      "├── batches.meta\n",
      "├── data_batch_1\n",
      "├── data_batch_2\n",
      "├── data_batch_3\n",
      "├── data_batch_4\n",
      "├── data_batch_5\n",
      "├── readme.html\n",
      "└── test_batch\n",
      "\n",
      "0 directories, 8 files\n"
     ]
    }
   ],
   "source": [
    "!wget -N https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/datasets/cifar-10-python.tar.gz\n",
    "!mkdir -p datasets\n",
    "!tar -xzf cifar-10-python.tar.gz -C datasets\n",
    "!tree ./datasets/cifar-10-batches-py"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据加载性能优化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "MindSpore为用户提供了多种数据加载方式，其中包括常用数据集加载、用户自定义数据集加载、MindSpore数据格式加载，详情内容请参考[数据集加载](https://www.mindspore.cn/doc/programming_guide/zh-CN/master/dataset_loading.html)。对于数据集加载，底层实现方式的不同，会导致数据集加载的性能存在差异，如下所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "|      | 常用数据集 | 用户自定义 | MindRecord |\n",
    "| :----: | :----: | :----: | :----: |\n",
    "| 底层实现 | C++ | Python | C++ |\n",
    "| 性能 | 高 | 中 | 高|"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 性能优化方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![data-loading-performance-scheme](https://gitee.com/mindspore/docs/raw/master/tutorials/training/source_zh_cn/advanced_use/images/data_loading_performance_scheme.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数据加载性能优化建议如下：\n",
    "\n",
    "- 已经支持的数据集格式优选内置加载算子，具体内容请参考[内置加载算子](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.html)，如果性能仍无法满足需求，则可采取多线程并发方案，请参考本文[多线程优化方案](#多线程优化方案)。\n",
    "\n",
    "- 不支持的数据集格式，优选转换为MindSpore数据格式后再使用`MindDataset`类进行加载（详细使用方法参考[API](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/dataset/mindspore.dataset.MindDataset.html)），具体内容请参考[将数据集转换为MindSpore数据格式](https://www.mindspore.cn/tutorial/training/zh-CN/master/advanced_use/convert_dataset.html)，如果性能仍无法满足需求，则可采取多线程并发方案，请参考本文[多线程优化方案](#多线程优化方案)。\n",
    "\n",
    "- 不支持的数据集格式，算法快速验证场景，优选用户自定义`GeneratorDataset`类实现（详细使用方法参考[API](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/dataset/mindspore.dataset.GeneratorDataset.html)），如果性能仍无法满足需求，则可采取多进程并发方案，请参考本文[多进程优化方案](#多进程优化方案)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 代码示例\n",
    "\n",
    "基于以上的数据加载性能优化建议，本次体验分别使用内置加载算子`Cifar10Dataset`类（详细使用方法参考[API](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/dataset/mindspore.dataset.Cifar10Dataset.html)）、数据转换后使用`MindDataset`类、使用`GeneratorDataset`类进行数据加载，代码演示如下：\n",
    "\n",
    "1. 使用内置算子`Cifar10Dataset`类加载CIFAR-10数据集，这里使用的是CIFAR-10二进制格式的数据集，加载数据时采取多线程优化方案，开启了4个线程并发完成任务，最后对数据创建了字典迭代器，并通过迭代器读取了一条数据记录。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'image': Tensor(shape=[32, 32, 3], dtype=UInt8, value=\n",
      "[[[181, 185, 194],\n",
      "  [184, 187, 196],\n",
      "  [189, 192, 201],\n",
      "  ...\n",
      "  [178, 181, 191],\n",
      "  [171, 174, 183],\n",
      "  [166, 170, 179]],\n",
      " [[182, 185, 194],\n",
      "  [184, 187, 196],\n",
      "  [189, 192, 201],\n",
      "  ...\n",
      "  [180, 183, 192],\n",
      "  [173, 176, 185],\n",
      "  [167, 170, 179]],\n",
      " [[185, 188, 197],\n",
      "  [187, 190, 199],\n",
      "  [193, 196, 205],\n",
      "  ...\n",
      "  [182, 185, 194],\n",
      "  [176, 179, 188],\n",
      "  [170, 173, 182]],\n",
      " ...\n",
      " [[176, 174, 185],\n",
      "  [172, 171, 181],\n",
      "  [174, 172, 183],\n",
      "  ...\n",
      "  [168, 171, 180],\n",
      "  [164, 167, 176],\n",
      "  [160, 163, 172]],\n",
      " [[172, 170, 181],\n",
      "  [171, 169, 180],\n",
      "  [173, 171, 182],\n",
      "  ...\n",
      "  [164, 167, 176],\n",
      "  [160, 163, 172],\n",
      "  [156, 159, 168]],\n",
      " [[171, 169, 180],\n",
      "  [173, 171, 182],\n",
      "  [177, 175, 186],\n",
      "  ...\n",
      "  [162, 165, 174],\n",
      "  [158, 161, 170],\n",
      "  [152, 155, 164]]]), 'label': Tensor(shape=[], dtype=UInt32, value= 6)}\n"
     ]
    }
   ],
   "source": [
    "cifar10_path = \"./datasets/cifar-10-batches-bin/train\"\n",
    "\n",
    "# create Cifar10Dataset for reading data\n",
    "cifar10_dataset = ds.Cifar10Dataset(cifar10_path,num_parallel_workers=4)\n",
    "# create a dictionary iterator and read a data record through the iterator\n",
    "print(next(cifar10_dataset.create_dict_iterator()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2. 使用`Cifar10ToMR`这个类将CIFAR-10数据集转换为MindSpore数据格式，这里使用的是CIFAR-10 python文件格式的数据集，然后使用`MindDataset`类加载MindSpore数据格式数据集，加载数据采取多线程优化方案，开启了4个线程并发完成任务，最后对数据创建了字典迭代器，并通过迭代器读取了一条数据记录。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'data': Tensor(shape=[1289], dtype=UInt8, value= [255, 216, 255, 224,   0,  16,  74,  70,  73,  70,   0,   1,   1,   0,   0,   1,   0,   1,   0,   0, 255, 219,   0,  67, \n",
      "   0,   2,   1,   1,   1,   1,   1,   2,   1,   1,   1,   2,   2,   2,   2,   2,   4,   3,   2,   2,   2,   2,   5,   4, \n",
      "   4,   3,   4,   6,   5,   6,   6,   6,   5,   6,   6,   6,   7,   9,   8,   6,   7,   9,   7,   6,   6,   8,  11,   8, \n",
      "   9,  10,  10,  10,  10,  10,   6,   8,  11,  12,  11,  10,  12,   9,  10,  10,  10, 255, 219,   0,  67,   1,   2,   2, \n",
      "   ...\n",
      "   ...\n",
      "   ...\n",
      "  39, 227, 206, 143, 241,  91, 196, 154, 230, 189, 125, 165, 105, 218,  94, 163, 124, 146,  11, 187,  29,  34, 217, 210, \n",
      "  23, 186,  56,  14, 192,  19, 181,   1,  57,  36,  14,  51, 211, 173, 105,   9, 191, 100, 212, 174, 122,  25, 110,  39, \n",
      "  11, 133, 193, 226, 169,  73,  36, 234,  69,  90, 222,  93,  31, 223, 115, 255, 217]), 'id': Tensor(shape=[], dtype=Int64, value= 46084), 'label': Tensor(shape=[], dtype=Int64, value= 5)}\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "from mindspore.mindrecord import Cifar10ToMR\n",
    "\n",
    "trans_path = \"./transform/\"\n",
    "\n",
    "if not os.path.exists(trans_path):\n",
    "    os.mkdir(trans_path)\n",
    "\n",
    "os.system(\"rm -f {}cifar10*\".format(trans_path))\n",
    "\n",
    "cifar10_path = './datasets/cifar-10-batches-py'\n",
    "cifar10_mindrecord_path = './transform/cifar10.record'\n",
    "\n",
    "cifar10_transformer = Cifar10ToMR(cifar10_path,cifar10_mindrecord_path)\n",
    "# execute transformation from CIFAR-10 to MindRecord\n",
    "cifar10_transformer.transform(['label'])\n",
    "\n",
    "# create MindDataset for reading data\n",
    "cifar10_mind_dataset = ds.MindDataset(dataset_file=cifar10_mindrecord_path,num_parallel_workers=4)\n",
    "# create a dictionary iterator and read a data record through the iterator\n",
    "print(next(cifar10_mind_dataset.create_dict_iterator()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "3. 使用`GeneratorDataset`类加载自定义数据集，并且采取多进程优化方案，开启了4个进程并发完成任务，最后对数据创建了字典迭代器，并通过迭代器读取了一条数据记录。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'data': Tensor(shape=[1], dtype=Int64, value= [0])}\n"
     ]
    }
   ],
   "source": [
    "def generator_func(num):\n",
    "    for i in range(num):\n",
    "        yield (np.array([i]),)\n",
    "\n",
    "# create GeneratorDataset for reading data\n",
    "dataset = ds.GeneratorDataset(source=generator_func(5),column_names=[\"data\"],num_parallel_workers=4)\n",
    "# create a dictionary iterator and read a data record through the iterator\n",
    "print(next(dataset.create_dict_iterator()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## shuffle性能优化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "shuffle操作主要是对有序的数据集或者进行过repeat的数据集进行混洗，MindSpore专门为用户提供了`shuffle`函数，其中设定的`buffer_size`参数越大，混洗程度越大，但时间、计算资源消耗也会大。该接口支持用户在整个pipeline的任何时候都可以对数据进行混洗，具体内容请参考[shuffle处理](https://www.mindspore.cn/doc/programming_guide/zh-CN/master/pipeline.html#shuffle)。但是因为底层的实现方式不同，该方式的性能不如直接在[内置加载算子](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.html)中设置`shuffle`参数直接对数据进行混洗。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 性能优化方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![shuffle-performance-scheme](https://gitee.com/mindspore/docs/raw/master/tutorials/training/source_zh_cn/advanced_use/images/shuffle_performance_scheme.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "shuffle性能优化建议如下：\n",
    "\n",
    "- 直接使用内置加载算子的`shuffle`参数进行数据的混洗。\n",
    "\n",
    "- 如果使用的是`shuffle`函数，当性能仍无法满足需求，可通过调大`buffer_size`参数的值来优化提升性能。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 代码示例\n",
    "\n",
    "基于以上的shuffle性能优化建议，本次体验分别使用内置加载算子`Cifar10Dataset`类的`shuffle`参数和`Shuffle`函数进行数据的混洗，代码演示如下："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. 使用内置算子`Cifar10Dataset`类加载CIFAR-10数据集，这里使用的是CIFAR-10二进制格式的数据集，并且设置`shuffle`参数为True来进行数据混洗，最后对数据创建了字典迭代器，并通过迭代器读取了一条数据记录。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'image': Tensor(shape=[32, 32, 3], dtype=UInt8, value=\n",
      "[[[213, 205, 194],\n",
      "  [215, 207, 196],\n",
      "  [219, 210, 200],\n",
      "  ...\n",
      "  [253, 254, 249],\n",
      "  [253, 254, 249],\n",
      "  [253, 254, 249]],\n",
      " [[218, 208, 198],\n",
      "  [220, 210, 200],\n",
      "  [222, 212, 202],\n",
      "  ...\n",
      "  [253, 254, 249],\n",
      "  [253, 254, 249],\n",
      "  [253, 254, 249]],\n",
      " [[219, 209, 198],\n",
      "  [222, 211, 200],\n",
      "  [224, 214, 202],\n",
      "  ...\n",
      "  [254, 253, 248],\n",
      "  [254, 253, 248],\n",
      "  [254, 253, 248]],\n",
      " ...\n",
      " [[135, 141, 139],\n",
      "  [135, 141, 139],\n",
      "  [146, 152, 150],\n",
      "  ...\n",
      "  [172, 174, 172],\n",
      "  [181, 182, 182],\n",
      "  [168, 168, 167]],\n",
      " [[113, 119, 117],\n",
      "  [109, 115, 113],\n",
      "  [117, 123, 121],\n",
      "  ...\n",
      "  [155, 159, 156],\n",
      "  [150, 155, 155],\n",
      "  [135, 140, 140]],\n",
      " [[121, 127, 125],\n",
      "  [117, 123, 121],\n",
      "  [121, 127, 125],\n",
      "  ...\n",
      "  [180, 184, 180],\n",
      "  [141, 146, 144],\n",
      "  [125, 130, 129]]]), 'label': Tensor(shape=[], dtype=UInt32, value= 8)}\n"
     ]
    }
   ],
   "source": [
    "cifar10_path = \"./datasets/cifar-10-batches-bin/train\"\n",
    "\n",
    "# create Cifar10Dataset for reading data\n",
    "cifar10_dataset = ds.Cifar10Dataset(cifar10_path,shuffle=True)\n",
    "# create a dictionary iterator and read a data record through the iterator\n",
    "print(next(cifar10_dataset.create_dict_iterator()))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2. 使用`shuffle`函数进行数据混洗，参数`buffer_size`设置为3，数据采用`GeneratorDataset`类自定义生成。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "before shuffle:\n",
      "[0 1 2 3 4]\n",
      "[1 2 3 4 5]\n",
      "[2 3 4 5 6]\n",
      "[3 4 5 6 7]\n",
      "[4 5 6 7 8]\n",
      "after shuffle:\n",
      "[2 3 4 5 6]\n",
      "[3 4 5 6 7]\n",
      "[1 2 3 4 5]\n",
      "[0 1 2 3 4]\n",
      "[4 5 6 7 8]\n"
     ]
    }
   ],
   "source": [
    "def generator_func():\n",
    "    for i in range(5):\n",
    "        yield (np.array([i,i+1,i+2,i+3,i+4]),)\n",
    "\n",
    "ds1 = ds.GeneratorDataset(source=generator_func,column_names=[\"data\"])\n",
    "print(\"before shuffle:\")\n",
    "for data in ds1.create_dict_iterator():\n",
    "    print(data[\"data\"])\n",
    "\n",
    "ds2 = ds1.shuffle(buffer_size=3)\n",
    "print(\"after shuffle:\")\n",
    "for data in ds2.create_dict_iterator():\n",
    "    print(data[\"data\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 数据增强性能优化"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在图片分类的训练中，尤其是当数据集比较小的时候，用户可以使用数据增强的方式来预处理图片，从而丰富数据集。MindSpore为用户提供了多种数据增强的方式，其中包括：\n",
    "\n",
    "- 使用内置C算子（`c_transforms`模块）进行数据增强。\n",
    "\n",
    "- 使用内置Python算子（`py_transforms`模块）进行数据增强。\n",
    "\n",
    "- 用户可根据自己的需求，自定义Python函数进行数据增强。\n",
    "\n",
    "具体的内容请参考[数据增强](https://www.mindspore.cn/doc/programming_guide/zh-CN/master/augmentation.html)。因为底层的实现方式不同，所以性能还是有一定的差异，如下所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "|   模块   | 底层接口 | 说明 |\n",
    "| :----: | :----: | :----: |\n",
    "| c_transforms | C++（基于OpenCV）| 性能高 |\n",
    "| py_transforms | Python（基于PIL） | 该模块提供了多种图像增强功能，并提供了PIL Image和Numpy数组之间的传输方法 |\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 性能优化方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![data-enhancement-performance-scheme](https://gitee.com/mindspore/docs/raw/master/tutorials/training/source_zh_cn/advanced_use/images/data_enhancement_performance_scheme.png)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "数据增强性能优化建议如下：\n",
    "\n",
    "- 优先使用`c_transforms`模块进行数据增强，因为性能最高，如果性能仍无法满足需求，可采取[多线程优化方案](#多线程优化方案)、[Compose优化方案](#Compose优化方案)或者[算子融合优化方案](#算子融合优化方案)。\n",
    "\n",
    "- 如果使用了`py_transforms`模块进行数据增强，当性能仍无法满足需求，可采取[多线程优化方案](#多线程优化方案)、[多进程优化方案](#多进程优化方案)、[Compose优化方案](#Compose优化方案)或者[算子融合优化方案](#算子融合优化方案)。\n",
    "\n",
    "- `c_transforms`模块是在C++内维护buffer管理，`py_transforms`模块是在Python内维护buffer管理。因为Python和C++切换的性能成本，建议不要混用算子。\n",
    "\n",
    "- 如果用户使用了自定义Python函数进行数据增强，当性能仍无法满足需求，可采取[多线程优化方案](#多线程优化方案)或者[多进程优化方案](#多进程优化方案)，如果还是无法提升性能，就需要对自定义的Python代码进行优化。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 代码示例\n",
    "\n",
    "基于以上的数据增强性能优化建议，本次体验分别使用`c_transforms`模块和自定义Python函数进行了数据增强，演示代码如下所示：\n",
    "\n",
    "1. 使用`c_transforms`模块进行数据增强，数据增强时采用多线程优化方案，开启了4个线程并发完成任务，并且采用了算子融合优化方案，使用`RandomResizedCrop`融合类替代`RandomResize`类和`RandomCrop`类。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "import mindspore.dataset.transforms.c_transforms as c_transforms\n",
    "import mindspore.dataset.vision.c_transforms as C\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "cifar10_path = \"./datasets/cifar-10-batches-bin/train\"\n",
    "\n",
    "# create Cifar10Dataset for reading data\n",
    "cifar10_dataset = ds.Cifar10Dataset(cifar10_path,num_parallel_workers=4)\n",
    "transforms = C.RandomResizedCrop((800,800))\n",
    "# apply the transform to the dataset through dataset.map()\n",
    "cifar10_dataset = cifar10_dataset.map(operations=transforms,input_columns=\"image\",num_parallel_workers=4)\n",
    "\n",
    "data = next(cifar10_dataset.create_dict_iterator())\n",
    "plt.imshow(data[\"image\"].asnumpy())\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "2. 使用自定义Python函数进行数据增强，数据增强时采用多进程优化方案，开启了4个进程并发完成任务。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "before map:\n",
      "[0 1 2 3 4]\n",
      "[1 2 3 4 5]\n",
      "[2 3 4 5 6]\n",
      "[3 4 5 6 7]\n",
      "[4 5 6 7 8]\n",
      "after map:\n",
      "[ 0  1  4  9 16]\n",
      "[ 1  4  9 16 25]\n",
      "[ 4  9 16 25 36]\n",
      "[ 9 16 25 36 49]\n",
      "[16 25 36 49 64]\n"
     ]
    }
   ],
   "source": [
    "def generator_func():\n",
    "    for i in range(5):\n",
    "        yield (np.array([i,i+1,i+2,i+3,i+4]),)\n",
    "\n",
    "ds3 = ds.GeneratorDataset(source=generator_func,column_names=[\"data\"])\n",
    "print(\"before map:\")\n",
    "for data in ds3.create_dict_iterator():\n",
    "    print(data[\"data\"])\n",
    "\n",
    "func = lambda x:x**2\n",
    "ds4 = ds3.map(operations=func,input_columns=\"data\",python_multiprocessing=True,num_parallel_workers=4)\n",
    "print(\"after map:\")\n",
    "for data in ds4.create_dict_iterator():\n",
    "    print(data[\"data\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 操作系统性能优化\n",
    "\n",
    "由于数据处理是在host端进行，那么机器或者操作系统本身的一些配置会对数据处理存在影响，主要有存储、NUMA架构、CPU（计算资源）几个方面。\n",
    "\n",
    "1. 存储\n",
    "\n",
    "    当数据集较大时，推荐使用固态硬盘对数据进行存储，能够减少存储I/O对数据处理的影响。\n",
    "\n",
    "    > 一般地，当数据集被加载之后，就会缓存在操作系统的page cache中，在一定程度上降低了存储开销，加快了后续epoch的数据读取。\n",
    "\n",
    "2. NUMA架构\n",
    "\n",
    "    非一致性内存架构(Non-uniform Memory Architecture)是为了解决传统的对称多处理(Symmetric Multi-processor)系统中的可扩展性问题而诞生的。NUMA系统拥有多条内存总线，于是将几个处理器通过内存总线与一块内存相连构成一个组，这样整个庞大的系统就可以被分为若干个组，这个组的概念在NUMA系统中被称为节点(node)。处于该节点中的内存被称为本地内存(local memory)，处于其他节点中的内存对于该组而言被称为外部内存(foreign memory)。因此每个节点访问本地内存和访问其他节点的外部内存的延迟是不相同的，在数据处理的过程中需要尽可能避免这一情况的发生。一般我们可以使用以下命令进行进程与node节点的绑定：\n",
    "\n",
    "    ```bash\n",
    "    numactl --cpubind=0 --membind=0 python train.py\n",
    "    ```\n",
    "\n",
    "3. CPU（计算资源）  \n",
    "\n",
    "    CPU对于数据处理的影响主要是计算资源的分配和CPU频率的设置两个方面。\n",
    "\n",
    "    - 计算资源的分配\n",
    "\n",
    "        当我们进行分布式训练时，一台设备机器上会启动多个训练进程，而这些训练进程会通过操作系统本身的策略进行计算资源的分配与抢占，当进程较多时，可能会由于计算资源的竞争而导致数据处理性能的下降，因此这时需要进行人工分配计算资源，避免各个进程的计算资源竞争。\n",
    "\n",
    "        ```bash\n",
    "        numactl --cpubind=0 python train.py\n",
    "        ```\n",
    "\n",
    "        或\n",
    "\n",
    "        ```bash\n",
    "        taskset -c 0-15 python train.py\n",
    "        ```\n",
    "\n",
    "        > `numactl`的方式较为粗粒度，直接指定`numa node id`，而`taskset`的方式是细粒度的，它能够直接指定`numa node`上的`cpu core`，其中0-15表示的`core id`从0到15。\n",
    "\n",
    "    - CPU频率设置\n",
    "\n",
    "        要想充分发挥host端CPU的最大算力，CPU频率的设置至关重要。一般地，linux内核支持调节CPU主频，降低功耗，已到达节能的效果。通过选择系统空闲状态不同的电源管理策略，可以实现不同程度降低服务器功耗。但是，更低的功耗策略意味着CPU唤醒更慢对性能影响更大。因此如果发现CPU模式为conservative或者powersave，可以使用cpupower设置CPU Performance模式，对数据处理的性能提升有非常大的效果。  \n",
    "\n",
    "        ```bash\n",
    "        cpupower frequency-set -g performance\n",
    "        ```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 性能优化方案总结\n",
    "\n",
    "### 多线程优化方案\n",
    "\n",
    "在数据pipeline过程中，相关算子一般都有线程数设置参数，来提升处理并发度，提升性能，例如：\n",
    "\n",
    "- 在数据加载的过程中，内置数据加载类有`num_parallel_workers`参数用来设置线程数。\n",
    "\n",
    "- 在数据增强的过程中，`map`函数有`num_parallel_workers`参数用来设置线程数。\n",
    "\n",
    "- 在Batch的过程中，`batch`函数有`num_parallel_workers`参数用来设置线程数。\n",
    "\n",
    "具体内容请参考[内置加载算子](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.html)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 多进程优化方案\n",
    "\n",
    "数据处理中Python实现的算子均支持多进程的模式，例如：\n",
    "\n",
    "- `GeneratorDataset`这个类默认是多进程模式，它的`num_parallel_workers`参数表示的是开启的进程数，默认为1，具体内容请参考[GeneratorDataset](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/dataset/mindspore.dataset.GeneratorDataset.html)。\n",
    "\n",
    "- 如果使用Python自定义函数或者`py_transforms`模块进行数据增强的时候，当`map`函数的参数`python_multiprocessing`设置为True时，此时参数`num_parallel_workers`表示的是进程数，参数`python_multiprocessing`默认为False，此时参数`num_parallel_workers`表示的是线程数，具体的内容请参考[内置加载算子](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.html)。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Compose优化方案\n",
    "\n",
    "Map算子可以接收Tensor算子列表，并将按照顺序应用所有的这些算子，与为每个Tensor算子使用的Map算子相比，此类“胖Map算子”可以获得更好的性能，如图所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![compose](https://gitee.com/mindspore/docs/raw/master/tutorials/training/source_zh_cn/advanced_use/images/compose.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 算子融合优化方案\n",
    "\n",
    "提供某些融合算子，这些算子将两个或多个算子的功能聚合到一个算子中。具体内容请参考[数据增强算子](https://www.mindspore.cn/doc/api_python/zh-CN/master/mindspore/mindspore.dataset.vision.html)，与它们各自组件的流水线相比，这种融合算子提供了更好的性能。如图所示："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![operator-fusion](https://gitee.com/mindspore/docs/raw/master/tutorials/training/source_zh_cn/advanced_use/images/operator_fusion.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 操作系统优化方案\n",
    "\n",
    "- 使用固态硬盘进行数据存储。\n",
    "\n",
    "- 将进程与node节点绑定。\n",
    "\n",
    "- 人工分配更多的计算资源。\n",
    "\n",
    "- 提高CPU运算频率。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 参考文献\n",
    "\n",
    "[1] Alex Krizhevsky. [Learning Multiple Layers of Features from Tiny Images](http://www.cs.toronto.edu/~kriz/learning-features-2009-TR.pdf)."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "MindSpore-1.1.1",
   "language": "python",
   "name": "mindspore-1.1.1"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
